package com.zbkj.service.manager.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zbkj.dal.base.constants.OrderConstants;
import com.zbkj.dal.base.enums.BooleanEnums;
import com.zbkj.dal.common.exception.CrmebException;
import com.zbkj.dal.common.utils.CrmebUtil;
import com.zbkj.dal.dao.*;
import com.zbkj.dal.entity.merchant.Merchant;
import com.zbkj.dal.entity.system.SystemBankInfo;
import com.zbkj.dal.entity.user.User;
import com.zbkj.dal.entity.user.UserBank;
import com.zbkj.dal.entity.user.UserWeekRecord;
import com.zbkj.service.manager.UserManager;
import com.zbkj.service.util.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Component
public class UserManagerImpl implements UserManager {

    @Resource
    private UserDao userDao;

    @Resource
    private RedissonClient redisson;

    @Resource
    private UserBankDao userBankDao;

    @Resource
    private MerchantDao merchantDao;

    @Resource
    private SystemBankInfoDao systemBankInfoDao;

    @Resource
    private UserWeekRecordDao userWeekRecordDao;

    @Override
    public User findByAccount(String account) {
        if (StringUtils.isEmpty(account)) {
            return null;
        }
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(User::getAccount, account);
        userWrapper.eq(User::getStatus, BooleanEnums.TRUE.getCode());
        return userDao.selectOne(userWrapper);
    }

    @Override
    public User findByUserId(Integer userId) {
        if (Objects.isNull(userId)) {
            return null;
        }
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(User::getId, userId);
        userWrapper.eq(User::getIsLogoff, BooleanEnums.FALSE.getCode());
        userWrapper.eq(User::getStatus, BooleanEnums.TRUE.getCode());
        return userDao.selectOne(userWrapper);
    }

    @Override
    public User availableUser(Integer userId) {
        User user = this.findByUserId(userId);
        if (user == null || !user.getStatus() || user.getIsLogoff()) {
            log.error("用户{}状态异常", userId);
            throw new CrmebException("用户异常");
        }
        return user;
    }

    @Override
    public List<User> findByUserId(List<Integer> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.in(User::getId, userIds);
        userWrapper.eq(User::getStatus, BooleanEnums.TRUE.getCode());
        return userDao.selectList(userWrapper);
    }

    @Override
    public User directSpreadUser(Integer userId) {
        User user = this.findByUserId(userId);
        if (Objects.isNull(user)) {
            log.error("未查询到用户id为：{}的用户信息", userId);
            throw new CrmebException("用户信息异常");
        }
        // 直接推荐人
        if (Objects.isNull(user.getSpreadUid())) {
            return null;
        }
        return this.findByUserId(user.getSpreadUid());
    }

    @Override
    public User indirectSpreadUser(Integer userId) {
        User directSpreadUser = this.directSpreadUser(userId);
        if (Objects.isNull(directSpreadUser) || Objects.isNull(directSpreadUser.getSpreadUid())) {
            return null;
        }
        return this.findByUserId(directSpreadUser.getSpreadUid());
    }

    @Override
    public Merchant spreadMerchant(Integer userId) {
        User user = this.findByUserId(userId);
        if (Objects.isNull(user.getSpreadMerchantId())) {
            return null;
        }
        return merchantDao.selectById(user.getSpreadMerchantId());
    }

    public UserWeekRecord selectWeeklyRecord(Integer userId) {
        // 根据用户上锁
        RLock lock = redisson.getLock(StrUtil.format("userWeekRecord.selectWeeklyRecord-{}", userId));
        if (!lock.tryLock()) {
            log.error("创建用户周记录失败, 请求参数{}", userId);
            throw new CrmebException("创建用户周记录失败，请稍后重试");
        }
        try {
            Integer weekStart = DateTimeUtil.weekStart();
            Integer weekEnd = DateTimeUtil.weekEnd();
            LambdaQueryWrapper<UserWeekRecord> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserWeekRecord::getUserId, userId);
            wrapper.ge(UserWeekRecord::getStartDate, weekStart);
            wrapper.le(UserWeekRecord::getEndDate, weekEnd);
            wrapper.eq(UserWeekRecord::getDeleted, BooleanEnums.FALSE.getCode());
            UserWeekRecord userWeekRecord = userWeekRecordDao.selectOne(wrapper);
            if (Objects.nonNull(userWeekRecord)) {
                return userWeekRecord;
            }
            userWeekRecord = UserWeekRecord.init(userId, weekStart, weekEnd);
            userWeekRecordDao.insert(userWeekRecord);
            return userWeekRecord;
        } catch (Throwable e) {
            log.error("创建用户周记录失败，请求参数{}，异常信息如下:", userId, e);
            throw e;
        } finally {
            lock.unlock();
        }
    }

    @Async
    public void addRecruitNum(Integer userId) {
        UserWeekRecord userWeekRecord = this.selectWeeklyRecord(userId);
        boolean result = userWeekRecordDao.addRecruitNum(userWeekRecord.getId());
        Assert.isTrue(result, "添加周数据推荐人数失败");
    }

    @Async
    public void addRecruitReward(Integer userId, BigDecimal reward) {
        UserWeekRecord userWeekRecord = this.selectWeeklyRecord(userId);
        boolean result = userWeekRecordDao.addRecruitReward(userWeekRecord.getId(), reward);
        Assert.isTrue(result, "添加周数据奖励金额失败");
    }

    @Async
    public void addOrderRecord(Integer userId, BigDecimal orderAmount) {
        UserWeekRecord userWeekRecord = this.selectWeeklyRecord(userId);
        boolean result = userWeekRecordDao.addOrderItem(userWeekRecord.getId(), orderAmount);
        Assert.isTrue(result, "添加周数据订单数据失败");
    }

    @Async
    public void cancelOrderRecord(Integer userId, BigDecimal orderAmount) {
        UserWeekRecord userWeekRecord = this.selectWeeklyRecord(userId);
        boolean result = userWeekRecordDao.cancelOrderItem(userWeekRecord.getId(), orderAmount);
        Assert.isTrue(result, "取消周数据订单数据失败");
    }

    @Override
    public List<User> firstFriends(Integer userId) {
        List<Integer> userIds = new ArrayList<>();
        userIds.add(userId);
        return firstFriends(userIds);
    }

    public List<User> firstFriends(List<Integer> userIds) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getSpreadUid, userIds);
        wrapper.eq(User::getIsLogoff, BooleanEnums.FALSE.getCode());
        wrapper.eq(User::getStatus, BooleanEnums.TRUE.getCode());
        return userDao.selectList(wrapper);
    }

    @Override
    public List<User> secondFriends(Integer userId) {
        List<User> users = this.firstFriends(userId);
        if (CollectionUtils.isEmpty(users)) {
            return new ArrayList<>();
        }
        List<Integer> userIds = users.stream().map(User::getId).distinct().collect(Collectors.toList());
        return this.firstFriends(userIds);
    }

    @Override
    public void updateShareProfit(Integer userId, Integer enable) {
        User user = this.findByUserId(userId);
        user.setEnableShareProfit(enable);
        userDao.updateById(user);
    }

    @Override
    public void addBlacklist(Integer userId) {
        User user = this.findByUserId(userId);
        user.setStatus(BooleanEnums.FALSE.isResult());
        userDao.updateById(user);
    }

    @Override
    public UserBank userBankcard(Integer userId) {
        LambdaQueryWrapper<UserBank> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBank::getUserId, userId);
        wrapper.eq(UserBank::getDeleted, BooleanEnums.FALSE.getCode());
        return userBankDao.selectOne(wrapper);
    }

    @Override
    public void bindUserBankcard(Integer userId, String accountName, String bankCode, String bankcardNo) {
        LambdaQueryWrapper<SystemBankInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SystemBankInfo::getBankNumber, bankCode);
        wrapper.eq(SystemBankInfo::getDeleted, BooleanEnums.FALSE.getCode());
        SystemBankInfo systemBankInfo = systemBankInfoDao.selectOne(wrapper);
        if (Objects.isNull(systemBankInfo)) {
            throw new CrmebException("银行信息异常，请稍后重试");
        }

        UserBank userBank = new UserBank();
        userBank.setBankcardNo(CrmebUtil.getOrderNo(OrderConstants.USER_BANK_ACCOUNT_NO_PREFIX));
        userBank.setUserId(userId);
        userBank.setAccountName(accountName);
        userBank.setBankcardNumber(bankcardNo);
        userBank.setBankNumber(systemBankInfo.getBankNumber());
        userBank.setBankName(systemBankInfo.getBankName());
        userBank.setCreateTime(LocalDateTime.now());
        userBank.setUpdateTime(LocalDateTime.now());
        userBank.setDeleted(BooleanEnums.FALSE.getCode());
        userBankDao.insert(userBank);
    }

    @Override
    public void unbindBankcard(Integer userId, String userBankcardNo) {
        LambdaQueryWrapper<UserBank> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBank::getUserId, userId);
        wrapper.eq(UserBank::getDeleted, BooleanEnums.FALSE.getCode());
        wrapper.eq(UserBank::getBankcardNo, userBankcardNo);
        UserBank userBank = userBankDao.selectOne(wrapper);
        if (Objects.isNull(userBank)) {
            throw new CrmebException("用户银行卡信息不存在，请稍后重试");
        }

        userBank.setDeleted(BooleanEnums.TRUE.getCode());
        userBankDao.updateById(userBank);
    }
}
